package com.example.springbootdemo.service.serviceImp;

import com.example.springbootdemo.constant.SystemConstant;
import com.example.springbootdemo.entity.Product;
import com.example.springbootdemo.mapper.ProductMapper;
import com.example.springbootdemo.service.ProductService;
import com.example.springbootdemo.utils.RedisUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections4.Put;
import org.redisson.api.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.util.StringUtils;

import javax.annotation.Resource;
import javax.mail.internet.InternetAddress;
import javax.xml.validation.Validator;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName: ProductServiceImpl
 * @Description:
 * @Author: TXW
 * @Date: 2025/1/10
 */
@Log4j2
@Service
public class ProductServiceImpl implements ProductService {
    @Resource
    private RedissonClient redissonClient;

    @Resource
    private ProductMapper productMapper;

    @Resource
    private RedisUtils redisUtils;

    private static final String LOCK_KEY = "product:lock:";
    private static final String USER_KEY = "userId:";


    /**
     * 模拟秒杀场景的接口
     * */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String disProduct(Integer id) throws UnknownHostException {
        // 修改: 使用产品ID作为锁的key，确保同一产品的操作是互斥的
        String uuid = UUID.randomUUID().toString();
        RLock lock = redissonClient.getLock(LOCK_KEY + id);
        try {
            lock.lock();
            Product product = productMapper.getProduct(id);

            if (product.getStore() <= 0){
                redissonClient.getMap(USER_KEY).put(uuid,"修改失败");
                log.info("东西已经抢完啦！库存剩余：{}，以后在来吧",  product.getStore());
                return "商品被抢完了！";
            }

            RMap<String, String> map = redissonClient.getMap(USER_KEY);
            if (map.containsKey(uuid)){
                return "您已经抢过该商品了！";
            }

            // 使用Redisson的原子性操作来更新库存
            RAtomicLong store = redissonClient.getAtomicLong(SystemConstant.STOCK_KEY + id);
            long currentStore = store.get();
            if (currentStore > 0) {
                store.decrementAndGet();
                product.setStore((int)currentStore - 1);
                productMapper.saveProduct(product);
                log.info("用户：{}获取产品成功! 库存剩余：{}", uuid, product.getStore());
                redissonClient.getMap(USER_KEY).put(uuid, "修改成功");
                return "恭喜您抢到了商品！";
            } else {
                redissonClient.getMap(USER_KEY).put(uuid, "修改失败");
                log.info("东西已经抢完啦！库存剩余：{}，以后在来吧", product.getStore());
                return "商品被抢完了！";
            }

//            product.setStore(product.getStore() - 1);
//            productMapper.saveProduct(product);
//            log.info("用户：{}获取产品成功! 库存剩余：{}", uuid, product.getStore());
//            redissonClient.getMap(USER_KEY).put(uuid,"修改成功");
//            return "恭喜您抢到了商品！";
        } finally {
            lock.unlock();
        }
    }

    @Override
    public String initProduct(Integer id) {
        //业务逻辑这块可能是个定时同步任务或者更新操作等、缓存预热
        int u = productMapper.initProduct(id);
        if (u != 0){
            Product product = productMapper.getProduct(id);
            RAtomicLong atomicLong = redissonClient.getAtomicLong(SystemConstant.STOCK_KEY + id);
            atomicLong.set(product.getStore());
            return "初始化成功";
        }
        return "初始化失败";
    }

    /**
     * 非秒杀功能获取详情
     * 秒杀环境下需要预热缓存
     * */
    @Override
    public Product getProduct(Integer id) {
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(SystemConstant.PRODUCT_CACHE + id);
        RLock rLock = readWriteLock.readLock(); //可并行执行
        try {
            rLock.lock();
            Product result = redisUtils.get(SystemConstant.PRODUCT + id, Product.class);
            if (result == null){
                Product product = productMapper.getProduct(id);
                if (product == null){ //防止缓存穿透
                    redisUtils.set(SystemConstant.PRODUCT + id, new Product(), SystemConstant.TIME_OUT_1MINUTE, TimeUnit.SECONDS);
                    return new Product();
                }
                //防止缓存击穿
                redisUtils.set(SystemConstant.PRODUCT + id, product, SystemConstant.TIME_OUT_1HOUR + randomTime(), TimeUnit.SECONDS);
                return product;
            } else {
                if (null == result.getId()){ //说明是赋值的空对象
                    redisUtils.expire(SystemConstant.PRODUCT + id, randomTime(), TimeUnit.SECONDS);
                }{
                    redisUtils.expire(SystemConstant.PRODUCT + id, randomTime(), TimeUnit.HOURS);
                }
                return result;
            }
        } finally {
            rLock.unlock();
        }
    }


    /**
     * 修改接口用于处理数据库、缓存数据不一致的问题
     *
     * 这里的更新的锁的key和查询详情的key是同一个：也就是控制了在操作数据和查询是线性执行的在更新完后才能获取数据
     * */
    @Override
    public int update(Product product) {
        //删除缓存
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(SystemConstant.PRODUCT_CACHE + product.getId());
        RLock rLock = readWriteLock.writeLock();
        try {
            rLock.lock();
            int update = productMapper.update(product);
            if (update != 0){
                redisUtils.set(SystemConstant.PRODUCT + product.getId(), product, SystemConstant.TIME_OUT_1HOUR + randomTime(), TimeUnit.SECONDS);
            }
            return update;
        } finally {
            rLock.unlock();
        }
    }

    /**
     * 5之内的随机数，代表随机五小时
     * */
    public int randomTime()  {
        return (int) (Math.random() * 5 + 1);
    }



}
